/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    irq.h
 *  @brief   IRQ header file
 *  @version v1.0
 *  @date    03. Apr. 2023
 ****************************************************************/

#ifndef __IRQ_H__
#define __IRQ_H__

#include <stdbool.h>
#include <stdint.h>

#include "core.h"

#ifdef __cplusplus
extern "C" {
#endif

#define CLINT_IRQ_NUM        16
#define CLIC_IRQ_NUM         128

#define INT_TRI_ATTR_POS         1
#define INT_TRI_ATTR_LEN         2
#define INT_SHV_ATTR_POS         0
#define INT_SHV_ATTR_LEN         1

enum irq_id {
	//NMI_EXPn                        =   -2,      /* NMI Exception */
	//User_Software_IRQn            = 0U,   /* User software interrupt */
	//Supervisor_Software_IRQn      = 1U,   /* Supervisor software interrupt */
	Machine_Software_IRQn         = 3U,   /* Machine software interrupt */
	User_Timer_IRQn               = 4U,   /* User timer interrupt */
	Supervisor_Timer_IRQn         = 5U,   /* Supervisor timer interrupt */
	Machine_Timer_IRQn            = 7U,   /* Machine Timer Interrupt */
	//Supervisor_External_IRQn      = 9U,   /* Supervisor external interrupt */
	Machine_External_IRQn         = 11U,  /* Machine external interrupt */
	
	RTC_IRQn                      = 16U,  /* RTC interrupt */
	WDT0_IRQn,                            /* WDT0 interrupt */
	WDT1_IRQn,                            /* WDT1 interrupt */
	TIMER0_IRQn,                          /* TIMER0 interrupt */
	TIMER1_IRQn                   = 20U,  /* TIMER1 interrupt */
	TIMER2_IRQn,                          /* TIMER2 interrupt */
	TIMER3_IRQn,                          /* TIMER3 interrupt */
	TIMER4_IRQn,                          /* TIMER4 interrupt */
	TIMER5_IRQn,                          /* TIMER5 interrupt */
	DMA_CH0_IRQn,                         /* DMA Channel 0 interrupt */
	DMA_CH1_IRQn,                         /* DMA Channel 1 interrupt */
	DMA_CH2_IRQn,                         /* DMA Channel 2 interrupt */
	DMA_CH3_IRQn,                         /* DMA Channel 3 interrupt */
	DMA_CH4_IRQn,                         /* DMA Channel 4 interrupt */
	DMA_CH5_IRQn                  = 30U,  /* DMA Channel 5 interrupt */
	DMA_CH6_IRQn,                         /* DMA Channel 6 interrupt */
	DMA_CH7_IRQn,                         /* DMA Channel 7 interrupt */
	SPI0_IRQn,                            /* SPI0 interrupt */
	SPI1_IRQn,                            /* SPI1 interrupt */
	SPI2_IRQn,                            /* SPI2 interrupt */
	SPI3_IRQn,                            /* SPI3 interrupt */
	I2C0_IRQn,                            /* I2C0 interrupt */
	I2C1_IRQn,                            /* I2C1 interrupt */
	UART0_IRQn,                           /* UART0 interrupt */
	UART1_IRQn                    = 40U,  /* UART1 interrupt */
	UART2_IRQn,                           /* UART2 interrupt */
	UART3_IRQn,                           /* UART3 interrupt */
	UART4_IRQn,                           /* UART4 interrupt */
	S0_ECC_ERR_1BIT_IRQn,                 /* LMU S0_ECC_ERR_1BIT interrupt */
	S0_ECC_ERR_XBIT_IRQn,                 /* LMU S0_ECC_ERR_xBIT interrupt */
	S1_ECC_ERR_1BIT_IRQn,                 /* LMU S1_ECC_ERR_1BIT interrupt */
	S1_ECC_ERR_XBIT_IRQn,                 /* LMU S1_ECC_ERR_xBIT interrupt */
	GPIO_IRQn,                            /* GPIO interrupt */
	GPIO_AUX_PORTA0_IRQn,                 /* GPIO_AUX_PORTA0 interrupt */
	GPIO_AUX_PORTA1_IRQn          = 50U,  /* GPIO_AUX_PORTA1 interrupt */
	GPIO_AUX_PORTA2_IRQn,                 /* GPIO_AUX_PORTA2 interrupt */
	GPIO_AUX_PORTA3_IRQn,                 /* GPIO_AUX_PORTA3 interrupt */
	GPIO_AUX_PORTA4_IRQn,                 /* GPIO_AUX_PORTA4 interrupt */
	GPIO_AUX_PORTA5_IRQn,                 /* GPIO_AUX_PORTA5 interrupt */
	GPIO_AUX_PORTA6_IRQn,                 /* GPIO_AUX_PORTA6 interrupt */
	GPIO_AUX_PORTA7_IRQn,                 /* GPIO_AUX_PORTA7 interrupt */
	GPIO_AUX_PORTA8_IRQn,                 /* GPIO_AUX_PORTA8 interrupt */
	GPIO_AUX_PORTA9_IRQn,                 /* GPIO_AUX_PORTA9 interrupt */
	GPIO_AUX_PORTA10_IRQn,                /* GPIO_AUX_PORTA10 interrupt */
	GPIO_AUX_PORTA11_IRQn         = 60U,  /* GPIO_AUX_PORTA11 interrupt */
	GPIO_AUX_PORTA12_IRQn,                /* GPIO_AUX_PORTA12 interrupt */
	GPIO_AUX_PORTA13_IRQn,                /* GPIO_AUX_PORTA13 interrupt */
	GPIO_AUX_PORTA14_IRQn,                /* GPIO_AUX_PORTA14 interrupt */
	GPIO_AUX_PORTA15_IRQn,                /* GPIO_AUX_PORTA15 interrupt */
	GPIO_AUX_PORTA16_IRQn,                /* GPIO_AUX_PORTA16 interrupt */
	GPIO_AUX_PORTA17_IRQn,                /* GPIO_AUX_PORTA17 interrupt */
	GPIO_AUX_PORTA18_IRQn,                /* GPIO_AUX_PORTA18 interrupt */
	GPIO_AUX_PORTA19_IRQn,                /* GPIO_AUX_PORTA19 interrupt */
	GPIO_AUX_PORTA20_IRQn,                /* GPIO_AUX_PORTA20 interrupt */
	GPIO_AUX_PORTA21_IRQn         = 70U,  /* GPIO_AUX_PORTA21 interrupt */
	GPIO_AUX_PORTA22_IRQn,                /* GPIO_AUX_PORTA22 interrupt */
	GPIO_AUX_PORTA23_IRQn,                /* GPIO_AUX_PORTA23 interrupt */
	PWM_STATUS0_IRQn,                     /* PWM_STATUS0 interrupt */
	PWM_STATUS1_IRQn,                     /* PWM_STATUS1 interrupt */
	PWM_FAULT_IRQn,                       /* PWM_FAULT interrupt */
	E_RELAY_STATUS_IRQn,                  /* E_RELAY_STATUS interrupt */
	INT_SARADC_IRQn,                      /* SAR_ADC interrupt */
	INT_I_OVF_IRQn,                       /* METER I_OVF interrupt */
	INT_SC_IA_IRQn,                       /* METER SC_IA interrupt */
	INT_SC_IB_IRQn                = 80U,  /* METER SC_IB interrupt */
	INT_SC_IC_IRQn,                       /* METER SC_IC interrupt */
	INT_U_ALARM_IRQn,                     /* METER U_ALARM interrupt */
	INT_ZC_IRQn,                          /* METER ZC interrupt */
	INT_NLOAD_IRQn,                       /* METER NLOAD interrupt */
	INT_NEG_EX_OVF_IRQn,                  /* METER NEG_EX_OVF interrupt */
	INT_POS_EX_OVF_IRQn,                  /* METER POS_EX_OVF interrupt */
	INT_SINGLE_DONE_IRQn,                 /* MONITOR SINGLE_DONE interrupt */
	INT_CONT_PINGDONE_IRQn,               /* MONITOR CONT_PINGDONE interrupt */
	INT_CONT_PANGDONE_IRQn,               /* MONITOR CONT_PANGDONE interrupt */
	INT_ZCP_PINGDONE_IRQn         = 90U,  /* MONITOR ZCP_PINGDONE interrupt */
	INT_ZCP_PANGDONE_IRQn,                /* MONITOR ZCP_PANGDONE interrupt */
	INT_ZCP_PINGABORT_IRQn,               /* MONITOR ZCP_PINGABORT interrupt */
	INT_ZCP_PANGABORT_IRQn,               /* MONITOR ZCP_PANGABORT interrupt */
	INT_ABN_DONE_IRQn,                    /* MONITOR ABN_DONE interrupt */
	INT_AHB_TIMEOUT_IRQn,                 /* MONITOR AHB_TIMEOUT interrupt */
	INT_AHB_HRESP_ERR_IRQn,               /* MONITOR AHB_HRESP_ERR interrupt */
	INT_ARC_IA,                           /* MONITOR INT_ARC_IA interrupt */
	INT_ARC_IB,                           /* MONITOR INT_ARC_IB interrupt */
	INT_ARC_IC,                           /* MONITOR INT_ARC_IC interrupt */
	INT_PVT_FALL                  = 100U, /* PMU INT_PVT_FALL interrupt */
	INT_PVT_RISE,                         /* PMU INT_PVT_RISE interrupt */

	MAXIMUM_CLIC_IRQn,
};

enum irq_tri_attr {
	IRQ_ATTR_LEVEL = 0,
	IRQ_ATTR_RISING_EDGE = 1,
	IRQ_ATTR_FALLING_EDGE = 3,
};

enum irq_shv_attr {
	IRQ_SHV_ATTR_DISABLE = 0,
	IRQ_SHV_ATTR_ENABLE = 1,
};


typedef struct irq_handle irq_handle_t;

typedef void (*irq_handler) (void *ptr);

struct irq_handle {
	irq_handler handler;
	void *priv;
};

/**
 * Enable irq.
 */
__ALWAYS_STATIC_INLINE void irq_enable(uint32_t irq_num)
{
#if defined(CONFIG_SYSTEM_SECURE)
	clic_enable_sirq((int32_t)irq_num);
#else
	clic_enable_irq((int32_t)irq_num);
#endif
}

/**
 * Disable irq.
 */
__ALWAYS_STATIC_INLINE void irq_disable(uint32_t irq_num)
{
#if defined(CONFIG_SYSTEM_SECURE)
	clic_disable_sirq(irq_num);
#else
	clic_disable_irq(irq_num);
#endif
}

/**
 * Configure irq attribute.
 */
void irq_cfg_attr(uint32_t irq_num, enum irq_tri_attr attr);

/**
 * Attach irq handler.
 */
void irq_attach(uint32_t irq_num, irq_handler handler, void *priv);

/**
 * detach irq handler.
 */
void irq_detach(uint32_t irq_num);

/**
 * Set irq priority
 */
__ALWAYS_STATIC_INLINE void irq_set_priority(uint32_t irq_num, uint32_t priority)
{
	clic_set_prio((int32_t)irq_num, priority);
}

/**
 * Gets whether the interrupt is enabled
 */
static inline bool irq_is_enabled(uint32_t irq_num)
{
	return (clic_get_enabled_irq((int32_t)irq_num) > 0) ? true : false;
}

static inline uint32_t irq_get_irq_num(void)
{
	return (__get_MCAUSE() & 0x3FF);
}

/**
 * Gets whether in irq context
 */
bool is_in_irq_context(void);

/**
 * Dispatching irq handlers
 */
void do_irq(void);

void SystemInit(void);

#ifdef __cplusplus
}
#endif

#endif /* __IRQ_H__ */

